// php_aceauth.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "php_aceauth.h"

#include <string>

#include "AceEnvironment.h"
#include "AceSession.h"

#include "OtpEnvironment.h"
#include "OtpSession.h"

#define ERR_INVALID_INPUT -1
#define ERR_FAIL_TO_LOCK  -2
#define ERR_FAIL_TO_CHECK -3
#define ERR_FAIL_TO_INIT  -4

PHP_MINIT_FUNCTION(aceauth);
PHP_MSHUTDOWN_FUNCTION(aceauth);
PHP_MINFO_FUNCTION(aceauth);
PHP_FUNCTION(aceauth_login);

ZEND_DECLARE_MODULE_GLOBALS(aceauth)

PHP_INI_BEGIN()
  STD_PHP_INI_ENTRY("aceauth.provider_type", "ace", PHP_INI_ALL, OnUpdateString, provider_type, zend_aceauth_globals, aceauth_globals)
  STD_PHP_INI_ENTRY("aceauth.opt_acf_path", "", PHP_INI_ALL, OnUpdateString, opt_acf_path, zend_aceauth_globals, aceauth_globals)
PHP_INI_END()

static function_entry aceauth_functions[] = {
	PHP_FE(aceauth_login, NULL)
	{NULL, NULL, NULL}
};

zend_module_entry aceauth_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
	STANDARD_MODULE_HEADER,
#endif
	PHP_ACEAUTH_EXTNAME,
	aceauth_functions,     /* Functions */
	PHP_MINIT(aceauth),
	PHP_MSHUTDOWN(aceauth),
	NULL,                  /* RINIT */
	NULL,                  /* RSHUTDOWN */
	PHP_MINFO(aceauth),    /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
	PHP_ACEAUTH_EXTVER,
#endif
	STANDARD_MODULE_PROPERTIES
};

extern "C" {
	ZEND_GET_MODULE(aceauth)
}

std::auto_ptr<auth::IAuthEnvironment> s_env;

#ifdef ZTS
/* {{{ php_zlib_init_globals
 */
static void php_aceauth_init_globals(zend_aceauth_globals *aceauth_globals_p TSRMLS_DC)
{
}
/* }}} */
#endif

PHP_MINIT_FUNCTION(aceauth)
{
#ifdef ZTS
  ts_allocate_id(&aceauth_globals_id, sizeof(zend_aceauth_globals), (ts_allocate_ctor) php_aceauth_init_globals, NULL);
#endif

  #include "GlobalConstants.h"

  REGISTER_INI_ENTRIES();

	try
	{
    if (CFG(provider_type) && (0 == stricmp(CFG(provider_type), "ace")))
    {
		  s_env.reset(new ace::CAceEnvironment());
    }
    else
    {
      s_env.reset(new otp::COtpEnvironment(CFG(opt_acf_path)));
    }
	}
	catch (auth::CAuthException& e)
	{
		// TODO: write debug log
	}	  

	return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(aceauth)
{
  UNREGISTER_INI_ENTRIES();

	try
	{
		s_env.reset();
	}
	catch (auth::CAuthException& e)
	{
		return FAILURE;
	}	

	return SUCCESS;
}

PHP_MINFO_FUNCTION(aceauth)
{
  php_info_print_table_start();
  php_info_print_table_row(2, "aceauth support", s_env.get () ? "enabled" : "disabled");
  php_info_print_table_row(2, "provider type", CFG(provider_type));
  php_info_print_table_row(2, "OTP ACF path", CFG(opt_acf_path));
  php_info_print_table_end();
}

PHP_FUNCTION(aceauth_login)
{
  if (s_env.get() == NULL) RETURN_LONG(ERR_FAIL_TO_INIT);

	char *user=NULL, *pass=NULL;
	int ulen = 0, plen = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &user, &ulen, &pass, &plen) == FAILURE ||
		!user || !pass || ulen==0 || plen==0)
	{		
		RETURN_LONG(ERR_INVALID_INPUT);
	}

	std::auto_ptr<auth::IAuthSession> session(s_env->createSession());

	session->open();

	std::string username(user, ulen), password(pass, plen);

	int ret = ACM_OK;

	if(!session->lock(username, &ret))
	{
		RETURN_LONG(ERR_FAIL_TO_LOCK);
	}

	if (!session->check(username, password, &ret))
	{
		RETURN_LONG(ERR_FAIL_TO_CHECK);
	}

	RETURN_LONG(ret);
}
